package com.yxw.yxnet_cd_center.customer_service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxw.yxnet_cd_center.common.constant.SessionConstants;
import com.yxw.yxnet_cd_center.common.dto.PageVO;
import com.yxw.yxnet_cd_center.common.utils.BaseDateTime;
import com.yxw.yxnet_cd_center.customer_service.dto.ChannelStatisticsQueryDTO;
import com.yxw.yxnet_cd_center.customer_service.dto.ExportChannelStatisticsDTO;
import com.yxw.yxnet_cd_center.customer_service.entity.YxCsChannelEntity;
import com.yxw.yxnet_cd_center.customer_service.entity.YxCsChannelStatisticsEntity;
import com.yxw.yxnet_cd_center.customer_service.entity.YxCsStandStatisticsEntity;
import com.yxw.yxnet_cd_center.customer_service.entity.YxcscClientFiledServiceEntity;
import com.yxw.yxnet_cd_center.customer_service.mapper.ChannelMapper;
import com.yxw.yxnet_cd_center.customer_service.mapper.ChannelStatisticsMapper;
import com.yxw.yxnet_cd_center.customer_service.mapper.YxcscClientFiledServiceMapper;
import com.yxw.yxnet_cd_center.customer_service.service.ChannelStatisticsService;
import com.yxw.yxnet_cd_center.customer_service.utils.PageUtils;
import com.yxw.yxnet_cd_center.customer_service.vo.ChannelStatisticsVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author fangmaoxin
 * @version 1.0
 * @date 2023年9月19日
 * 渠道活跃度统计-服务类
 */
@Slf4j
@Service
public class ChannelStatisticsServiceImpl extends ServiceImpl<ChannelStatisticsMapper, YxCsChannelStatisticsEntity> implements ChannelStatisticsService {

    @Autowired
    private ChannelStatisticsMapper channelStatisticsMapper;

    @Autowired
    private YxcscClientFiledServiceMapper clientFiledServiceMapper;

    @Autowired
    private ChannelMapper channelMapper;

    private static final String DATETIME_FORMATTER = "yyyy-MM-dd HH:mm:ss";

    /**
     * 查询渠道活跃度统计列表
     */
    @Override
    @Transactional
    public PageVO<ChannelStatisticsVo> selectChannelStatisticsList(ChannelStatisticsQueryDTO dto) {
        Page<YxCsChannelStatisticsEntity> page = new Page<>(dto.getCurrPage(), dto.getPageSize());
        LambdaQueryWrapper<YxCsChannelStatisticsEntity> queryWrapper = getWrapper(dto.getChannelName(), dto.getCreateTimeStart(), dto.getCreateTimeEnd());
        // 执行查询
        page = baseMapper.selectPage(page, queryWrapper);
        List<YxCsChannelStatisticsEntity> entityList = page.getRecords();
        // 使用BeanUtils.copyProperties()将属性复制到ChannelStatisticsVo列表
        List<ChannelStatisticsVo> statisticsVoList = new ArrayList<>();
        if (entityList != null && !entityList.isEmpty()) {
            statisticsVoList = BeanUtil.copyToList(entityList, ChannelStatisticsVo.class);
        }
        return PageUtils.get(page, statisticsVoList);
    }

    /**
     * 导出表格
     */
    @Override
    public void exportExcel(HttpServletResponse response, ExportChannelStatisticsDTO dto) {

        // 查出数据
        List<YxCsChannelStatisticsEntity> list;
        LambdaQueryWrapper<YxCsChannelStatisticsEntity> queryWrapper = getWrapper(dto.getChannelName(), dto.getCreateTimeStart(), dto.getCreateTimeEnd());
        list = channelStatisticsMapper.selectList(queryWrapper);

        log.info("=======================开始导出文件=========================");
        // 获取当前时间并格式化为数字形式
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String timestamp = now.format(formatter);
        // 导出文件名后添加当前导出的时间
        String fileName = String.format("渠道活跃统计表%s.xls", timestamp);
        // 调用工具类
        try {
            // 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

            // 创建工作簿
            Workbook workbook = new HSSFWorkbook();
            Sheet sheet = workbook.createSheet("渠道活跃度统计");

            // 写入表头
            String[] headers = {"统计编号", "渠道名称", "今日咨询数", "历史咨询数", "今日处理率", "历史处理率", "比前一日活跃度",
                    "创建时间", "更新时间", "统计日期"};
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < headers.length; i++) {
                headerRow.createCell(i).setCellValue(headers[i]);
            }
            SimpleDateFormat formatter2 = new SimpleDateFormat(DATETIME_FORMATTER);

            // 写入数据
            int rowIndex = 1;
            for (YxCsChannelStatisticsEntity entity : list) {
                Row row = sheet.createRow(rowIndex);
                row.createCell(0).setCellValue(entity.getStatisticsId()); // 统计编号
                row.createCell(1).setCellValue(entity.getChannelName()); // 渠道名称
                row.createCell(2).setCellValue(entity.getDayConsultCnt()); // 今日咨询数
                row.createCell(3).setCellValue(entity.getHisConsultCnt()); // 历史咨询数
                row.createCell(4).setCellValue(entity.getDayHandleRate()); // 今日处理率
                row.createCell(5).setCellValue(entity.getHisHandleRate()); // 历史处理率
                row.createCell(6).setCellValue(entity.getActiveRate()); // 比前一日活跃度
                row.createCell(7).setCellValue(formatter2.format(entity.getCreateTime())); // 创建时间
                row.createCell(8).setCellValue(formatter2.format(entity.getUpdateTime())); // 更新时间
                row.createCell(9).setCellValue(entity.getPDay()); // 统计日期yyyyMMdd
                rowIndex++;
            }
            // 输出到响应流
            try (OutputStream outputStream = response.getOutputStream()) {
                workbook.write(outputStream);
            }
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static LambdaQueryWrapper<YxCsChannelStatisticsEntity> getWrapper(String dto, String dto1, String dto2) {
        LambdaQueryWrapper<YxCsChannelStatisticsEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件
        if (StringUtils.isNotBlank(dto)) {
            queryWrapper.eq(YxCsChannelStatisticsEntity::getChannelName, dto);
        }
        // 设置筛选条件
        queryWrapper.ge(StringUtils.isNotBlank(dto1), YxCsChannelStatisticsEntity::getCreateTime, BaseDateTime.getDate(dto1))
                .le(StringUtils.isNotBlank(dto2), YxCsChannelStatisticsEntity::getCreateTime, BaseDateTime.getDate(dto2))
                .orderByDesc(YxCsChannelStatisticsEntity::getCreateTime);// 设置排序方式
        return queryWrapper;
    }

    /**
     * 更新渠道活跃度统计数据
     */
    @Override
    @Transactional
    public void insertChannelStatistics() {
        List<YxcscClientFiledServiceEntity> sessionEntityList = clientFiledServiceMapper.selectList(new LambdaQueryWrapper<>());

        if (sessionEntityList != null && !sessionEntityList.isEmpty()) {
            Map<String, List<YxcscClientFiledServiceEntity>> channelSessionMap = new HashMap<>();
            for (YxcscClientFiledServiceEntity sessionEntity : sessionEntityList) {
                List<YxcscClientFiledServiceEntity> channelSessionList = channelSessionMap.getOrDefault(
                        sessionEntity.getChannelCode(), new ArrayList<>()
                );
                channelSessionList.add(sessionEntity);
                channelSessionMap.put(sessionEntity.getChannelCode(), channelSessionList);
            }
            LocalDate today = LocalDate.now();
            LocalDate yesterday = today.minusDays(1);
            LocalDateTime todayStart = LocalDate.now().atStartOfDay();
            LocalDateTime todayEnd = LocalDateTime.now().with(LocalTime.MAX).plusSeconds(1);
            List<YxCsChannelStatisticsEntity> statisticsList = new ArrayList<>();
            for (Map.Entry<String, List<YxcscClientFiledServiceEntity>> entry : channelSessionMap.entrySet()) {
                String channelCode = entry.getKey();
                List<YxcscClientFiledServiceEntity> channelSessionList = entry.getValue();
                // 计算历史咨询数
                long hisConsultCnt = getHisConsultCnt(channelCode, sessionEntityList);
                // 其他计算逻辑
                long todayConsultCnt = 0; // 今日咨询数
                long yesterdayConsultCnt = 0; // 昨日咨询数
                long handledCnt = 0; // 历史处理数
                long handledCntToday = 0; // 今日处理数
                for (YxcscClientFiledServiceEntity sessionEntity : channelSessionList) {
                    todayConsultCnt = getTodayConsultCnt(sessionEntity, channelSessionList, today);
                    yesterdayConsultCnt = getTodayConsultCnt(sessionEntity, channelSessionList, yesterday);
                    handledCnt = getHandledCnt(sessionEntity, channelSessionList);
                    handledCntToday = getHandledCntToday(sessionEntity, channelSessionList);
                }
                // 计算历史处理率
                double hisHandleRate = getHisHandleRate(hisConsultCnt, handledCnt);
                // 计算今日处理率
                double dayHandleRate = getHandleRate(todayConsultCnt, handledCntToday);
                String activeRateStr = getActiveRateStr(yesterdayConsultCnt, todayConsultCnt);
                // 创建 YxCsChannelStatisticsEntity 对象
                YxCsChannelStatisticsEntity statistics = getEntity(channelCode, (int) todayConsultCnt, (int) hisConsultCnt,
                        dayHandleRate, hisHandleRate, activeRateStr);
                statisticsList.add(statistics);
            }
            List<YxCsChannelStatisticsEntity> selectedList = baseMapper.selectList(new LambdaQueryWrapper<>());
            if (!selectedList.isEmpty()) {
                // 找出selectedList中创建时间是最新的一条
                YxCsChannelStatisticsEntity latestEntity = selectedList.stream()
                        .max(Comparator.comparing(YxCsChannelStatisticsEntity::getCreateTime))
                        .orElse(null);

                if (latestEntity != null) {
                    Date createDate = latestEntity.getCreateTime();
                    LocalDateTime creationDateTime = LocalDateTime.ofInstant(createDate.toInstant(), ZoneId.systemDefault());
                    LocalDate creationDate = creationDateTime.toLocalDate();

                    if (creationDate.isEqual(today)) {
                        // 如果创建时间是今天之内，则删除今天的所有数据
                        baseMapper.delete(new LambdaQueryWrapper<YxCsChannelStatisticsEntity>()
                                .ge(YxCsChannelStatisticsEntity::getCreateTime, todayStart)
                                .le(YxCsChannelStatisticsEntity::getCreateTime, todayEnd));
                        super.saveBatch(statisticsList);
                    } else if (creationDate.isEqual(yesterday)){
                        // 如果创建时间是在昨天，则直接执行批量新增
                        super.saveBatch(statisticsList);
                    } else {
                        // 如果创建时间是更早的日期，则根据业务逻辑进行相应处理
                        super.saveBatch(statisticsList);
                    }
                }
            }
        }
    }

    /**
     * 计算历史日处理率
     */
    private static double getHisHandleRate(long hisConsultCnt, double handledCnt) {
        double hisHandleRate = 0;
        if (hisConsultCnt > 0) {
            hisHandleRate = handledCnt / hisConsultCnt * 100;
        }
        return hisHandleRate;
    }

    /**
     * 计算日处理率
     */
    private static double getHandleRate(long todayConsultCnt, double handledCntToday) {
        double dayHandleRate = 0;
        if (todayConsultCnt > 0) {
            dayHandleRate = handledCntToday / todayConsultCnt * 100;
        }
        return dayHandleRate;
    }

    /**
     * 设置实体类字段
     */
    private YxCsChannelStatisticsEntity getEntity(String channelCode, int todayConsultCnt, int hisConsultCnt, double dayHandleRate, double hisHandleRate, String activeRateStr) {
        YxCsChannelStatisticsEntity statistics = new YxCsChannelStatisticsEntity();
        statistics.setChannelCode(channelCode);
        // 获取对应的 channel_name\id
        statistics.setChannelId(getChannelId(channelCode));
        statistics.setChannelName(getChannelName(channelCode));
        // 设置今日咨询数和历史咨询数
        statistics.setDayConsultCnt(todayConsultCnt);
        statistics.setHisConsultCnt(hisConsultCnt);
        // 设置今日处理率和历史处理率
        statistics.setDayHandleRate(String.format("%.2f", dayHandleRate) + "%");
        statistics.setHisHandleRate(String.format("%.2f", hisHandleRate) + "%");
        // 设置比前一日活跃度
        statistics.setActiveRate(activeRateStr);
        // 将时间戳格式化为yyyyMMdd日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String pDay = dateFormat.format(new Date());
        statistics.setPDay(Long.valueOf(pDay));
        // 更新或插入记录
        statistics.setCreateTime(new Date());
        statistics.setUpdateTime(new Date());
        return statistics;
    }


    /**
     * 计算历史处理数
     */
    private static long getHandledCnt(YxcscClientFiledServiceEntity sessionEntity, List<YxcscClientFiledServiceEntity> channelSessionList) {
        return channelSessionList.stream()
                .filter(s -> s.getChannelCode().equals(sessionEntity.getChannelCode()))
                .filter(s -> s.getState() == SessionConstants.ENDED) // state为5表示处理完成
                .count();
    }

    /**
     * 计算今日处理数
     */
    private static long getHandledCntToday(YxcscClientFiledServiceEntity sessionEntity, List<YxcscClientFiledServiceEntity> channelSessionList) {
        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
        LocalDateTime todayEnd = LocalDateTime.now().with(LocalTime.MAX).plusSeconds(1);

        return channelSessionList.stream()
                .filter(s -> s.getChannelCode().equals(sessionEntity.getChannelCode()))
                .filter(s -> s.getState() == SessionConstants.ENDED)
                .filter(s -> {
                    LocalDateTime sessionEndTime = LocalDateTime.ofInstant(Instant.ofEpochSecond((s.getUpdateTime() / 1000)), ZoneId.systemDefault());
                    return sessionEndTime.isAfter(todayStart) && sessionEndTime.isBefore(todayEnd);
                })
                .count();
    }

    /**
     * 计算今日咨询数
     */
    private static long getTodayConsultCnt(YxcscClientFiledServiceEntity sessionEntity, List<YxcscClientFiledServiceEntity> channelSessionList, LocalDate today) {
        LocalDateTime todayStart = today.atStartOfDay();
        LocalDateTime todayEnd = todayStart.plusDays(1);

        return channelSessionList.stream()
                .filter(s -> s.getChannelCode().equals(sessionEntity.getChannelCode()))
                .filter(s -> {
                    LocalDateTime createTime = LocalDateTime.ofInstant(Instant.ofEpochSecond((s.getCreateTime() / 1000)), ZoneId.systemDefault());
                    return createTime.isAfter(todayStart) && createTime.isBefore(todayEnd);
                })
                .count();
    }

    /**
     * 计算历史咨询数
     */
    private static long getHisConsultCnt(String channelCode, List<YxcscClientFiledServiceEntity> channelSessionList) {
        return channelSessionList.stream()
                .filter(s -> channelCode.equals(s.getChannelCode()))
                .count();
    }


    /**
     * 计算渠道活跃度-日活跃（和前一天相比）统计数据
     */
    private static String getActiveRateStr(long yesterdayConsultCnt, long todayConsultCnt) {
        double activeRate;
        if (yesterdayConsultCnt == 0 && todayConsultCnt != 0) {
            activeRate = (double) todayConsultCnt * 100;
        } else if (yesterdayConsultCnt != 0) {
            double difference = (double) todayConsultCnt - yesterdayConsultCnt;
            activeRate = (difference / Math.abs(yesterdayConsultCnt)) * 100;
        } else {
            activeRate = 0.0;
        }
        return String.format("%.0f%%", activeRate);
    }

    /**
     * 根据 channelCode查询对应的 channel_name
     */
    private String getChannelName(String channelCode) {
        LambdaQueryWrapper<YxCsChannelEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxCsChannelEntity::getChannelCode, channelCode);
        YxCsChannelEntity yxCsChannelEntity = channelMapper.selectOne(wrapper);
        return yxCsChannelEntity != null ? yxCsChannelEntity.getChannelName() : null;
    }

    /**
     * 根据 channelCode查询对应的 channel_id
     */
    private Long getChannelId(String channelCode) {
        LambdaQueryWrapper<YxCsChannelEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxCsChannelEntity::getChannelCode, channelCode);
        YxCsChannelEntity yxCsChannelEntity = channelMapper.selectOne(wrapper);
        return yxCsChannelEntity != null ? yxCsChannelEntity.getId() : null;
    }
}

